package org.tuskit.model {
    import com.adobe.cairngorm.model.ModelLocator;
    
    import mx.collections.ArrayCollection;
    import mx.collections.ListCollectionView;
    import mx.collections.XMLListCollection;
    import mx.controls.Alert;
    
    import org.tuskit.control.EventNames;
    import org.tuskit.util.CairngormUtils;
    import org.tuskit.validators.ServerErrors;

    [Bindable]
    public class TuskitModelLocator implements ModelLocator {
        
        //LocatorState
        public static const LOCATOR_INIT      	:Array = [0];
        public static const LOCATOR_LOGIN     	:Array = [1];
        
        public static const LOCATOR_MAIN      	:Array = [2];
        public static const LOCATOR_DEVELOPER	:Array = [2,0];
        public static const LOCATOR_CUSTOMER 	:Array = [2,1];
        public static const LOCATOR_ADMIN     	:Array = [2,2];
		
		//User Groups
		public static const ADMIN :int = 1;
		public static const DEVELOPER :int = 2;
		public static const CUSTOMER :int = 3;
		
        //
        //Public properties
        //
        public var currentUser:User; //logged on user
        
        public var selectedUserId:int = -1; //if of a user selected in user grid
        
        public var currentUserGroups:ArrayCollection = new ArrayCollection([]);
        
        public var users:ListCollectionView = new ArrayCollection([]);

        public var groups:ListCollectionView;

        public var memberships:ListCollectionView;

        public var usersAndNone:ListCollectionView;

        public var groupsAndNone:ListCollectionView;

        public var userIDMap:Object;

        public var groupIDMap:Object;
                
        
        //for server-based validation
        public var userErrors:ServerErrors;

        public var currentLocation:Array = LOCATOR_LOGIN;
        
        public var isInTransitionState:Boolean = false;
        
        //CommandColletions
        
        public var commandsArray:Array = new Array();
        
        
        public function executeCommandsArray():void {
        	var commandObject:Object;
        	for each (commandObject in commandsArray) {
        		commandObject.command.execute(commandObject.event);
        	}
        }
        
        public function commandsArrayDelete(command:Object):void {
        	var i:int = 0;
        	for (i; i< commandsArray.length; i++) {
        		if (commandsArray[i]['command'] == command)
        		commandsArray.splice(i,1);
        		break
        	}
        }
        
        public function reset():void {
        	currentUser = null;
        	currentUserGroups.source = [];
        	users = null;
        	groups = null;
        	memberships = null;
        	usersAndNone = null;
        	groupsAndNone = null;
        	userIDMap = null;
        	groupIDMap = null;
        }

		public function getUsersGroupsMemberships():void {
        	isInTransitionState=true;
            CairngormUtils.dispatchEvent(EventNames.LIST_USERS, {toCommandsArray: true});
	        CairngormUtils.dispatchEvent(EventNames.LIST_GROUPS, {toCommandsArray: true});
            executeCommandsArray();
		}

		public function setMemberships(list:XMLList):void {
            var membershipsArray:Array = [];
            var item:XML;
            for each (item in list) {
                var membership:Membership = Membership.fromXML(item);
                membershipsArray.push(membership);
            }
            memberships = new ArrayCollection(membershipsArray);
		}
		
	   	public function updateMembership(membership:Membership):void {
            for (var i:int = 0; i < memberships.length; i++) {
                var ithMembership:Membership = Membership(memberships.getItemAt(i));
                if (ithMembership.id == membership.id) {
                    memberships.setItemAt(memberships, i);
                    break;
                }
            }
       	}
       
       public function removeMembership(membership:Membership):void {
            for (var i:int = 0; i < memberships.length; i++) {
                var ithMembership:Membership = Membership(memberships.getItemAt(i));
                if (ithMembership.id == membership.id) {
                    ithMembership.user.removeMembership(ithMembership);
                    ithMembership.group.removeMembership(ithMembership);
                    memberships.removeItemAt(i);
                    break;
                }
            }
        }

			
        public function setUsers(list:XMLList):void {
            userIDMap = {};
            userIDMap[0] = User.NONE;
            var usersArray:Array = [];
            var item:XML;
            for each (item in list) {
                var user:User = User.fromXML(item);
                usersArray.push(user);
                userIDMap[user.id] = user;
            }
            users = new ArrayCollection(usersArray);
            
            //get full copy of array and prepend it with empty user
            var usersAndNoneArray:Array = usersArray.slice(0);
            usersAndNoneArray.splice(0, 0, User.NONE);
            
            usersAndNone = new ArrayCollection(usersAndNoneArray);
        }

        public function setGroups(list:XMLList):void {
            groupIDMap = {};
            groupIDMap[0] = Group.NONE;
            var groupsArray:Array = [];
            var item:XML;
            for each (item in list) {
                var group:Group = Group.fromXML(item);
                groupsArray.push(group);
                groupIDMap[group.id] = group;
            }
            groups = new ArrayCollection(groupsArray);
            var groupsAndNoneArray:Array = groupsArray.slice(0);
            groupsAndNoneArray.splice(0, 0, Group.NONE);
            groupsAndNone = new ArrayCollection(groupsAndNoneArray);
        }
        
        public function getUser(userID:int):User {
            if (userIDMap == null) return null;
            return userIDMap[userID];
        }
    
        public function getGroup(groupID:int):Group {
            if (groupIDMap == null) return null;
            return groupIDMap[groupID];
        }
        

        //
        //Singleton stuff
        //
        private static var modelLocator:TuskitModelLocator;

        public static function getInstance():TuskitModelLocator {
            if (modelLocator == null) {
                modelLocator = new TuskitModelLocator();
            }
            return modelLocator;
        }
        
        //The constructor should be private, but this is not possible in
        //ActionScript 3.0.  So, throwing an Error if a second
        //TuskitModelLocator is created is the best we can do to implement
        //the Singleton pattern.
        public function TuskitModelLocator() {
            if (modelLocator != null) {
                throw new Error(
                  "Only one TuskitModelLocator instance may be instantiated.");
            }
        }
    }
}